/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 *
 */
package com.godenwater.recv.server.summit;

import cn.gov.mwr.sl651.*;
import cn.gov.mwr.sl651.body.DataItem;
import cn.gov.mwr.sl651.body.Up36Body;
import cn.gov.mwr.sl651.command.UpCommand;
import cn.gov.mwr.sl651.parser.HexParser;
import cn.gov.mwr.sl651.utils.ByteUtil;
import cn.gov.mwr.sl651.utils.StcdParser;
import com.godenwater.yanyu.YYBuilder;
import com.godenwater.recv.model.CommonMessage;
import com.godenwater.recv.server.all.RtuCodecFactory;
import org.apache.commons.lang.StringUtils;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoConnector;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.SocketSessionConfig;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * An UDP client taht just send thousands of small messages to a UdpServer.
 * <p>
 * This class is used for performance test purposes. It does nothing at all, but
 * send a message repetitly to a server.
 *
 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
 */
public class SummitClient extends IoHandlerAdapter implements Runnable {

    private Logger logger = LoggerFactory.getLogger(SummitClient.class);

    /**
     * The connector
     */
    private IoConnector connector;

    /**
     * The session
     */
    private static IoSession session;

    private boolean received = false;

    private UpCommand cmd = new UpCommand();

    private byte upDown = Symbol.UP;

    private int mPort = 5380;

    private SummitClient() {

    }

    /**
     * Create the UdpClient's instance
     */
    public SummitClient(int _port) {
        connector = new NioSocketConnector();
        connector.getFilterChain().addLast("codec",
                new ProtocolCodecFilter(new RtuCodecFactory(false, "comm")));
        connector.setHandler(this);

        SocketSessionConfig dcfg = (SocketSessionConfig) connector
                .getSessionConfig();
        dcfg.setWriteTimeout(30);

        mPort = _port;
        // 创建连接
        //
        ConnectFuture connFuture = connector.connect(new InetSocketAddress(
                "127.0.0.1", 5380));//5800,6688,5888

        // 等待是否连接成功，相当于是转异步执行为同步执行。
        connFuture.awaitUninterruptibly();

        // 获取session
        session = connFuture.getSession();

        cmd.setCenterAddr(ByteUtil.HexStringToBinary("FF"));
        cmd.setStationAddr(ByteUtil.HexStringToBinary("0011223344"));
        cmd.setPassword(ByteUtil.HexStringToBinary("FFFF"));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void exceptionCaught(IoSession session, Throwable cause)
            throws Exception {
        // cause.printStackTrace();
        logger.info(">> Client 会话出现异常  " + session.getRemoteAddress() + " \t"
                + cause.getMessage(), cause);
    }

    public void viewInfo(HexParser parser, IMessage message) throws Exception {

        IMessageHeader header = message.getHeader();
        IMessageBody body = parser.parse36Body(message.getBody().getContent());

        Up36Body body36 = (Up36Body) body;

        System.out.println("******* 中心站查询遥测站实时数据 *******");
        System.out.println("原始包长度：" + header.getBodySize() + "字节");
        // System.out
        // .println("原始包信息：" + );
        System.out.println("中心站地址："
                + ByteUtil.toHexString(header.getCenterAddr()));
        System.out.println("水文特征码：00，水文测站编码："
                + StcdParser.parseStcd(header.getStationAddr()));
        System.out.println("密码：" + ByteUtil.toHexString(header.getPassword()));
        System.out.println("功能码：" + ByteUtil.toHexString(header.getFuncCode()));
        System.out.println("流水号：" + body36.getSerialId() + "，发报时间："
                + body36.getSendDate());

    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void messageReceived(IoSession session, Object message)
            throws Exception {
        received = true;

        // 纯粹只处理报文，此消息体已经被解码为单体报文
        CommonMessage msg = (CommonMessage) message;
        Object msgheader = msg.getHeader();
        if (msgheader instanceof cn.gov.mwr.sl651.header.HexHeader) {

            IMessageHeader header = (IMessageHeader) msg
                    .getHeader();
            String hHeader = HydroBuilder.toHexString(header,
                    Symbol.DOWN);
            String hBody = ByteUtil.toHexString(msg.getContent());
            String hEof = ByteUtil.toHexString(msg.getEOF());
            String hCrc = ByteUtil.toHexString(msg.getCRC());
            System.out.println(hHeader + hBody + hEof + hCrc);

        } else if (msgheader instanceof cn.gov.mwr.sl651.header.AscHeader) {

            IMessageHeader header = (IMessageHeader) msg
                    .getHeader();

            String hHeader = HydroBuilder.toHexString(header,
                    Symbol.DOWN);
            String hBody = ByteUtil.toHexString(msg.getContent());
            String hEof = ByteUtil.toHexString(msg.getEOF());
            String hCrc = ByteUtil.toHexString(msg.getCRC());
            System.out.println(hHeader + hBody + hEof + hCrc);

        } else if (msgheader instanceof com.godenwater.yanyu.YYMessageHeader) {

            com.godenwater.yanyu.IMessageHeader header = (com.godenwater.yanyu.IMessageHeader) msg
                    .getHeader();

            String hHeader = YYBuilder.toHexString(header,
                    Symbol.DOWN);
            String hBody = ByteUtil.toHexString(msg.getContent());
            String hEof = ByteUtil.toHexString(msg.getEOF());
            String hCrc = ByteUtil.toHexString(msg.getCRC());
            System.out.println(hHeader + hBody + hEof + hCrc);

        } else {
            // 未知的报文

        }

        // IParser parser = new HexParser();
        // // viewInfo(new HexParser(),msg);
        // byte eof = msg.getEOF();
        // if (eof == Symbol.EOT) {
        // System.out.println(">> ST "
        // + parser.parseStcd(header.getStationAddr()) + " 确认报文。");
        //
        // } else if (eof == Symbol.ESC) {
        // System.out.println(">> ST "
        // + parser.parseStcd(header.getStationAddr())
        // + " 确认报文，需保持在线！");
        //
        // } else if (eof == Symbol.ESC) {
        // System.out.println(">> ST "
        // + parser.parseStcd(header.getStationAddr())
        // + " 查询报文，需保持在线！");
        // }

    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void messageSent(IoSession session, Object message) throws Exception {
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void sessionClosed(IoSession session) throws Exception {
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void sessionCreated(IoSession session) throws Exception {
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void sessionIdle(IoSession session, IdleStatus status)
            throws Exception {
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void sessionOpened(IoSession session) throws Exception {
    }

    public void run() {
        int i = 1;
        try {

            String line = "";
            line = "68 31 68 BE 56 56 50 14 40 80 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 09 20 02 14 43 21 10 58 12 00 00 00 00 21 16 ";
            //line = "683568bd42136400408001233d0000b106b106b106b106b106b106b106b106b106b106b106b10600000000161507178130105912000000006d16";
            line="68006896421364004096bbaa170701006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07006f07ff16";
            sendMessage(StringUtils.replace(line, " ", ""));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void stop() {
        if (connector.isActive()) {
            connector.dispose(true);
        }
    }

    protected void sendCommand(String command) {
        cmd.setBodyStartBit(Symbol.STX);

        IMessage message = null;
        // ------------------------------
        if (StringUtils.isNotEmpty(command)) {

            if (command.length() > 2) {
                // 直接发送命令
                session.write(ByteUtil.HexStringToBinary(command));
                return;
            }

            if (message != null) {
                session.write(message);
                System.out.println(this + "-----遥测站发送报文-----功能码：0x" + command
                        + "-----");
                cmd.printHexString(message);
                System.out.println("-----------------------------------------");
            }
        }
    }

    public void sleep(int seconds) {
        try {
            Thread.sleep(seconds);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void sendYY06Message() {

        String hexString = "7E11FF067B0001AAAAAA1510291417FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF176622";
        byte[] message = ByteUtil.HexStringToBinary(hexString);
        session.write(message);

        sleep(100);

        hexString = "7E11FF067B0002FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1789A5";
        byte[] message2 = ByteUtil.HexStringToBinary(hexString);
        session.write(message2);

        sleep(100);

        hexString = "7E11FF067B0003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF178564";
        byte[] message3 = ByteUtil.HexStringToBinary(hexString);
        session.write(message3);

        sleep(100);

        hexString = "7E11FF067B000403F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F817D788";
        byte[] message4 = ByteUtil.HexStringToBinary(hexString);
        session.write(message4);

        sleep(100);

        hexString = "7E11FF067B000503F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F803F817DB49";
        byte[] message5 = ByteUtil.HexStringToBinary(hexString);
        session.write(message5);

    }

    public void sendYY0AMessage() {

        String hexString = "7E10020E3F150704090000290000900000000000000000000000000069696969696969696969696969696969696969696969696912200000000014000000FFFF0003C953";

        hexString = "7e100c0a7b0001dddddd1502122206220622062206220622062206220622062206220622062219221922202220222022202224222422242224135313531353100210031003104010401040104210421054105410541054120412041204120412041204120412041204120412041204120412041204120412241224122417ec39";

        byte[] message = ByteUtil.HexStringToBinary(hexString);
        session.write(message);

        // hexString =
        // "7E11FF067B0002FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1789A5";
        // byte[] message2 = ByteUtil.HexStringToBinary(hexString);
        // session.write(message2);

    }

    /**
     * 6.6.4.2　链路维持报
     */
    public IMessage send2FMessage() {

        cmd.setFuncCode(new byte[]{(byte) 0x2F});
        cmd.setBodyStartBit(Symbol.STX);
        cmd.setEof(Symbol.ETX);
        return cmd.send2FMessage(1, null);
    }

    /**
     * 6.6.4.3　测试报
     */
    public IMessage send30Message() {
        cmd.setBodyStartBit(Symbol.STX);
        cmd.setEof(Symbol.ETX);

        List<DataItem> items = new ArrayList();
        DataItem item = new DataItem();

        // 20H //当前降水量PJ
        String value = "123.45";
        int decimal = HydroBuilder.buildDecimal(value);
        value = StringUtils.replace(value, ".", "");
        byte[] pjData = ByteUtil.str2Bcd(value);
        byte datalen = HydroBuilder.buildDataLength(pjData.length, decimal);

        item.setLabel(new byte[]{(byte) 0x20, datalen});
        item.setValue(pjData);
        items.add(item);

        // 38H //电压// VT
        value = "12.00";
        value = StringUtils.replace(value, ".", "");
        byte[] vtData = ByteUtil.str2Bcd(value);
        byte vtDataLen = HydroBuilder.buildDataLength(vtData.length, decimal);
        DataItem item2 = new DataItem();
        item2.setLabel(new byte[]{(byte) 0x38, vtDataLen});
        item2.setValue(vtData);
        items.add(item2);

        String stcd = "0011110000";
        String sttp = "P";

        SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmm");
        String viewDate = sdf.format(new Date(System.currentTimeMillis()));

        return cmd.send30Message(1, null, stcd, sttp, viewDate, items);

    }

    /**
     * 人工置数报，测试通过
     */
    public void send31Message() {

        // String hexString =
        // "7E7E010040548583000A310036020008140508120018F1F1000000000148F0F014050811050418000005F5C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF035AFE";

        String hexString = "7E7E010020321200000A31002A029999140531150001F1F1002032120048F0F014053114050418000005F4600000000000000000000000000326C32C";
        hexString = "7E7E010020345600000A310036020031120510090018F1F1002034560048F0F012051008050418000005F5C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF033D7A";
        byte[] message = ByteUtil.HexStringToBinary(hexString);
        session.write(message);
    }

    public void send32Message() {
        String hexstr = "7E7EFF0000000003FFFF32005E020024130503160000F1F1000000000348F0F01305031500F460000000000000000000000000F5C0000B000B000B000B000B000BFFFF000B000B000B000B000BF0F0130503160020190000001F190000002619000030391A0000123812126003B98B";
        hexstr = "7E7E020040544500303932002502822CA20826150200F1F1004054450050F0F0A208261500201900003826190547463812119403E124";
        hexstr = "7E7E010011420410000A320025020023140917110018F1F1001142041048F0F0140917110020190011002619002522381213390370C4";
        hexstr = "7E7E010020152800000A320041020035140829170002F1F1002015280048F0F014082917002019000000F0F01408291605F460000000000000000000000000F0F01408291700261900294038121315035A2A";
        hexstr = "7E7E010020346800000A320041020035140829170002F1F1002034680048F0F014082917002019000002F0F01408291605F460000000000200000000000000F0F014082917002619002898381213040397EA";
        hexstr = "7E7E010090000006000A320047020003150326160004F1F1009000000648F0F015032616002019000412F0F01503261505F46000FFFFFFFF1E005400000200F0F0150326160026190005243923FFFFFFFF38121171033497";
        hexstr = "7E7E010090000006000A310042020002150326230001F1F1009000000648F0F0150326220504180000052219FFFFFFFFFFFF00000000003000000000000000000000000000000000000000000000000003753B";
        hexstr = "7E7E010090000006000A320041020003150326230003F1F1009000000648F0F015032623002019000030F0F01503262205F460FFFF001E0000000000000000F0F0150326230026190000303812117103121E";
        hexstr = "7E7EFF0001724600E240340035020012150327100002F1F1000172460048F0F01503270905F460000000000000000000000000F0F0150327100026190000003812141103E837";
        hexstr = "7E7EFF0001722400E240340035020161150327090003F1F1000172240048F0F01503270805F460121E0E0A0A060E161406141AF0F01503270900261902647838121367031399";
        hexstr = "7E7E010090000007000A31004202000A150327140001F1F1009000000748F0F0150327130504180000052219000000000000000000000000000000000000000000000000000000000000000000000000030BCA";
        hexstr = "7E7E010090000001000A32004102000B150327140002F1F1009000000148F0F015032714002019000100F0F01503271305F460000000000000000000000000F0F01503271400261900013038121171035012";
        hexstr = "7E7E010090000001000A320047020007150329120008F1F1009000000148F0F015032912002019000000F0F01503291105F460000000000000000000000000F0F0150329120026190002283923FFFFFFFF3812117103512B";
        byte[] message = ByteUtil.HexStringToBinary(hexstr);
        session.write(message);

    }

    public void send33Message() {
        // String hexstr =
        // "01464630303132333435363738303030413333303034310230303034313330333037303631383330535420303031323334353637382048205454203133303330373036313820505220303030322E302056542031322E3333200335383337";
        String hexstr = "013432303031313232333334343034443233333030343102303032423133303330383130313835315354203030313132323333343420482054542031333033303831303138205A20303031322E39392056542031322E3332200332453939";
        // 雨量加报
        hexstr = "7E7E3C8888666601000033001C020005130104134800F1F1888866660150F0F01301041348261900003403A777";
        // 水位加报
        hexstr = "7E7E3C8888666601000033001D020006130104135201F1F1888866660150F0F0130104135239230002409003BAFF";
        byte[] message = ByteUtil.HexStringToBinary(hexstr);
        session.write(message);

    }

    /**
     * 小时报
     */
    public void sendMessage(String hexString) {

        hexString = StringUtils.replace(hexString, " ", "");
        byte[] message = ByteUtil.HexStringToBinary(hexString);
        session.write(message);
    }

    /**
     * The main method : instanciates a client, and send N messages. We sleep
     * between each K messages sent, to avoid the server saturation.
     *
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {

        // 将数据长度与前四位整合
        // String hexString =
        // "7E 7E AA AA AA AA AA AA 12 34 33 00 57 02 07 CC 16 09 05 15 10 02 F1 F1 AA AA AA AA AA 48 F0 F0 16 09 05 15 10 F4 60 00 32 00 00 00 00 00 00 00 00 00 00 F5 C0 0A FD 0A FD FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 26 19 00 00 50 20 19 00 00 50 1A 19 00 00 50 39 1A 00 28 13 38 12 11 40 03 7E 9B";
        // hexString = StringUtils.replace(hexString, " ", "");
        // System.out.println(">> hex string " + hexString);

        // ----------------------------------------------------------
        for (int i = 1; i <= 1; i++) {
            SummitClient client = new SummitClient(5017);
            Thread thread = new Thread(client);
            thread.start();
        }


    }
}
